﻿using FunArts.EasyDevOps.Rcl.Service;
using FunArts.EasyDevOps.Rcl.Utils;
using FunArts.EasyDevOps.Shared.Models.SshClient;
using FunArts.EasyDevOps.Shared.Models.SshClient.Command;
using FunArts.EasyDevOps.Shared.Models.SshClient.CommandResult;
using FunArts.EasyDevOps.Shared.Utils;
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.JavaScript;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using static System.Net.WebRequestMethods;

namespace FunArts.EasyDevOps.Platforms.Windows.Service.Impl
{
    /// <summary>
    /// 应用程序windows平台ssh连接实现
    /// </summary>
    public class SshClientService: ISshClientService
    {
        public SshClientConnectInfo SshClientConnectInfo { get; set; }
        private SshClient _sshClient;
        private SftpClient _sftpClient;
        /// <summary>
        /// 交互式shell
        /// </summary>
        private ShellStream _shellStream;

        //private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected=> _sshClient?.IsConnected??false;

        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="errMsg">失败返回错误信息</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool Connect(out string errMsg)
        {
            errMsg=string.Empty;
            if (!SshClientConnectInfo.CheckParam(out errMsg))
            {
                return false;
            }
            _sshClient = new SshClient(SshClientConnectInfo.Host, SshClientConnectInfo.User, SshClientConnectInfo.Pwd);
            _sftpClient = new SftpClient(SshClientConnectInfo.Host, SshClientConnectInfo.User, SshClientConnectInfo.Pwd);
            //_cancellationTokenSource.CancelAfter(30000);// 超时时间
            try
            {
                _sshClient.Connect();
                _sftpClient.Connect();

                //// 创建交互式 Shell 流（模拟终端）
                //_shellStream = _sshClient.CreateShellStream("xterm", 80, 24, 800, 600, 1024);

                //// 等待 Shell 初始化完成（读取欢迎消息）
                //_shellStream.Expect(new Regex(@"[$#]")); // 等待提示符（$ 或 #）
            }
            catch (Exception ex)
            {
                errMsg = $"连接失败!{ex.Message}";
                return false;
            }

            if (_sshClient.IsConnected && _sftpClient.IsConnected)
            {
                //修复环境变量
                CheckAndFixBashrcCommand checkAndFixBashrcCommand = new CheckAndFixBashrcCommand();
                var linuxCommandResultBase = ExecuteCommand(checkAndFixBashrcCommand);
                if (linuxCommandResultBase.Output.Trim() == "false")
                {
                    //重新连接
                    Disconnect();
                    return Connect(out errMsg);
                }
                linuxCommandResultBase=ExecuteCommand(new SystemInfoCommand());
                if (!linuxCommandResultBase.Error.IsNullOrWhiteSpace())
                {
                    errMsg = "获取系统信息出错!";
                    return false;
                }
                foreach (var item in linuxCommandResultBase.Output.Split('\n'))
                {
                    if (item.StartsWith("NAME="))
                    {
                        var index = item.IndexOf("\"") + 1;
                        var systemVersion = item.Substring(index, item.LastIndexOf("\"") - index);
                        if(systemVersion.ToLower().Contains("ubuntu"))
                        {
                            SshClientConnectInfo.SystemVersionType = EasyDevOps.Shared.Models.Enums.SystemVersionTypeEnum.Ubuntu;
                        }
                        if (systemVersion.ToLower().Contains("centos"))
                        {
                            SshClientConnectInfo.SystemVersionType = EasyDevOps.Shared.Models.Enums.SystemVersionTypeEnum.CentOS;
                        }
                    }
                }
                return true;
            }
            else
            {
                errMsg = "连接服务器失败！";
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            _shellStream?.Close();
            _sshClient?.Disconnect();
            _sftpClient?.Disconnect();
        }
        /// <summary>
        /// 执行Linux命令
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public LinuxCommandResultBase ExecuteCommand<T>(T command) where T : ILinuxCommand
        {
            LinuxCommandResultBase linuxCommandResultBase = new LinuxCommandResultBase();
            if (!IsConnected)
            {
                if(!Connect(out string errMsg))
                {
                    linuxCommandResultBase.Error = errMsg;
                    return linuxCommandResultBase;
                }
            }

            string commandText = command.BuildCommand(SshClientConnectInfo.SystemVersionType);
            var cmd = _sshClient.CreateCommand(commandText);
            var result = cmd.Execute();

            linuxCommandResultBase.Output = result;
            linuxCommandResultBase.ExitStatus = cmd.ExitStatus;
            linuxCommandResultBase.Error = cmd.Error;
            //try
            //{
            //    // 发送命令到交互式 Shell
            //    _shellStream.WriteLine(commandText);

            //    // 等待命令执行完成（直到出现提示符）
            //    string output = _shellStream.Expect(new Regex(@"[$#]"));

            //    // 移除命令本身和最后的提示符
            //    output = output.Replace(commandText, "").Trim();
            //    output = Regex.Replace(output, @"[$#]\s*$", "").Trim();

            //    linuxCommandResultBase.Output = output;
            //    linuxCommandResultBase.ExitStatus = 0; // 交互式 Shell 无法直接获取 ExitStatus，需手动解析
            //    linuxCommandResultBase.Error = "";
            //}
            //catch (Exception ex)
            //{
            //    linuxCommandResultBase.Error = $"执行命令失败: {ex.Message}";
            //}
            return linuxCommandResultBase;
        }
        /// <summary>
        /// 执行Linux命令
        /// </summary>
        /// <param name="createCommandFunc"></param>
        /// <returns></returns>
        public LinuxCommandResultBase ExecuteCommand(Func<ILinuxCommand> createCommandFunc)
        {
            ILinuxCommand linuxCommand = createCommandFunc();
            return ExecuteCommand(linuxCommand);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileStream">需要上传的文件流</param>
        /// <param name="remoteFilePath">服务器路径</param>
        /// <exception cref="Exception"></exception>
        public void UploadFile(byte[] fileData, string remoteFilePath)
        {
            if (!_sftpClient.IsConnected)
            {
                throw new Exception("SFTP连接未建立！");
            }
            
            // 检查远程目录是否存在，如果不存在则创建
            var directoryPath = LinuxPathUtils.GetDirectoryName(remoteFilePath);
            if (!_sftpClient.Exists(directoryPath))
            {
                _sftpClient.CreateDirectory(directoryPath);
            }

            // 检查文件是否已存在，如果存在则删除
            if (_sftpClient.Exists(remoteFilePath))
            {
                _sftpClient.DeleteFile(remoteFilePath);
            }

            using (MemoryStream stream = new MemoryStream(fileData))
            {
                _sftpClient.UploadFile(stream, remoteFilePath);
            }
        }

        public async Task UploadFileAsync(byte[] fileData, string remoteFilePath, Action<double> progressCallback = null)
        {
            if (!_sftpClient.IsConnected)
            {
                throw new Exception("SFTP连接未建立！");
            }

            // 检查远程目录是否存在，如果不存在则创建
            var directoryPath = LinuxPathUtils.GetDirectoryName(remoteFilePath);
            if (!_sftpClient.Exists(directoryPath))
            {
                _sftpClient.CreateDirectoryRecursive(directoryPath);
            }

            // 检查文件是否已存在，如果存在则删除
            if (_sftpClient.Exists(remoteFilePath))
            {
                _sftpClient.DeleteFile(remoteFilePath);
            }

            using (MemoryStream stream = new MemoryStream(fileData))
            {
                long fileSize = stream.Length;
                long totalBytesRead = 0;
                int bufferSize = (int)Math.Min(fileSize, 1024 * 1024);
                byte[] buffer = new byte[bufferSize];
                int bytesRead;

                // 打开远程文件流
                using (var remoteFileStream = _sftpClient.OpenWrite(remoteFilePath))
                {
                    while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        await remoteFileStream.WriteAsync(buffer, 0, bytesRead);
                        totalBytesRead += bytesRead;

                        // 计算上传进度并回调
                        if (progressCallback != null)
                        {
                            double progress = (double)totalBytesRead / fileSize * 100;
                            progressCallback(progress);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="remoteFilePath">服务器文件路径</param>
        /// <returns>文件流字符串</returns>
        /// <exception cref="Exception"></exception>
        public byte[] DownloadFile(string remoteFilePath)
        {
            if (!_sftpClient.IsConnected)
            {
                throw new Exception("SFTP连接未建立！");
            }

            if (!_sftpClient.Exists(remoteFilePath))
            {
                return null;
            }

            using (Stream fileStream = _sftpClient.OpenRead(remoteFilePath))
            using (var memoryStream = new MemoryStream())
            {
                fileStream.CopyTo(memoryStream);

                byte[] fileBytes = memoryStream.ToArray();

                return fileBytes;
            }
        }

        /// <summary>
        /// 查找文件
        /// </summary>
        /// <param name="directory"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public LinuxCommandResultBase FindFile(string directory, string fileName)
        {
            ILinuxCommand linuxCommand=new FindCommand(directory, fileName);
            return ExecuteCommand(linuxCommand);
        }
        /// <summary>
        /// 加载目录
        /// </summary>
        /// <param name="node"></param>
        public async Task LoadDirectoryTree(DirectoryNode node)
        {
            await Task.Run(() => {
                node.Children.Clear();
                ListDirectoryCommand listDirectoryCommand = new ListDirectoryCommand() { Directory=node.FullPath };
                
                var linuxCommandResultBase=(this as ISshClientService).ExecuteCommand<ListDirectoryCommand, FileSystemResult>(listDirectoryCommand);
                if (linuxCommandResultBase.ExitStatus != 0)
                {
                    throw new Exception(linuxCommandResultBase.Error);
                }
                var directoryNodes=linuxCommandResultBase.OutData.Select(f => new DirectoryNode
                {
                    Name = f.Name,
                    FullPath = (node.FullPath == "/" ? "" : node.FullPath) + $"/{f.Name}",
                    IsDir = f.IsDirectory,
                    Children = new List<DirectoryNode>()
                });
                if (directoryNodes.Any())
                {
                    node.Children.AddRange(directoryNodes);
                }
                //var command = _sshClient.RunCommand($"ls -l {node.FullPath}");
                //if (command.ExitStatus == 0)
                //{
                //    var lines = command.Result.Split('\n');
                //    foreach (var line in lines)
                //    {
                //        if (!string.IsNullOrWhiteSpace(line))
                //        {
                //            // 使用正则表达式匹配 ls -l 的输出
                //            var match = Regex.Match(line, @"^([d-])([rwx-]+)\s+\d+\s+\w+\s+\w+\s+\d+\s+\w+\s+\d+\s+[\d:]+\s+(.+)$");
                //            if (match.Success)
                //            {
                //                bool isDir = match.Groups[1].Value == "d"; // 判断是否是目录
                //                string fileName = match.Groups[3].Value;  // 提取文件名

                //                var dirPath = (node.FullPath == "/" ? "" : node.FullPath) + $"/{fileName}";
                //                var childNode = new DirectoryNode
                //                {
                //                    Name = fileName,
                //                    FullPath = dirPath,
                //                    IsDir = isDir,
                //                    Children = new List<DirectoryNode>()
                //                };
                //                node.Children.Add(childNode);

                //                // 如果需要递归加载子目录，可以调用 LoadDirectoryTree
                //                // LoadDirectoryTree(_sshClient, childNode);
                //            }
                //        }
                //    }
                //}
            });
        }

        

    }
}
